﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.IO;


namespace CSMDeamon
{
    class AppMonitor
    {
        int processTimeOut = 0;

        public int ProcessTimeOut
        {
            get { return processTimeOut; }
        }
        bool running = false;
        public int RestartDelay = 10000;

        #region 属性
        int MAX_TIME_OUT = 10;                //超过若干秒未收到站机看门狗消息，则超时
        int WATCHDOG_SEND_INTERVAL = 2000;    //看门狗发送间隔(毫秒）
        int THREAD_SLEEP_INTERVAL = 1000;

        string processName = "";
        public string ProcessName
        {
            get { return processName; }
            set { processName = value; }
        }

        string processPath;
        public string ProcessPath
        {
            get { return processPath; }
            set { processPath = value; }
        }

        public int WatchDogInterval
        {
            get { return WATCHDOG_SEND_INTERVAL; }
            set { WATCHDOG_SEND_INTERVAL = value; }
        }

        public int DetectInterval
        {
            get { return THREAD_SLEEP_INTERVAL; }
            set { THREAD_SLEEP_INTERVAL = value; }
        }

        public int MaxTimeOut
        {
            get { return MAX_TIME_OUT; }
            set { MAX_TIME_OUT = value; }
        }

        public String State
        {
            get;
            private set;
        }
        #endregion

        String updatePath;
        String updateDir;
        String runDir;
        public AppMonitor()
        {
            runDir = AppDomain.CurrentDomain.BaseDirectory;
            updateDir = Path.Combine(runDir, "Update");
            updatePath = Path.Combine(runDir, "Update\\Ver.xml");

        }

        public void Start()
        {
            running = true;
            Thread thrMonitor = new Thread(new ThreadStart(MonitorProc));
            thrMonitor.IsBackground = true;
            thrMonitor.Start();
        }

        public void Stop()
        {
            running = false;
        }

        private void MonitorProc()
        {
            int nCount = 0;
            bool force = false;

            while (running)
            {
                try
                {
                    //判断进程是否存在
                    if (ProcessRunning())
                    {
                        //判断看门狗是是否超时
                        if (processTimeOut > MAX_TIME_OUT)
                        {
                            WriteLog("等待超时.");
                            //先通知进程关闭，然后重启进程
                            if (KillProcess(force))
                            {
                                StartProcess();
                                force = false;
                                processTimeOut = 0;
                            }
                            else
                            {
                                //如果正常关闭失败，(等待下一个超时周期，强制杀死进程）
                                force = true;
                                processTimeOut = 0;
                            }
                        }
                    }
                    else
                    {
                        //启动进程
                        
                        if (File.Exists(updatePath))
                        {
                            this.State = String.Format("检查到更新文件,正在更新");
                            MoveFiles(updateDir);
                        }
                        else
                        {
                            this.State = String.Format("启动延时中[{0}][{1}]", RestartDelay,this.ProcessName);
                            Thread.Sleep(RestartDelay);
                        }
                        this.State = String.Format("正在启动{0}",this.ProcessName);
                        StartProcess();
                    }
                    String.Format("超时时间{0},超时计数{1}", MaxTimeOut, ProcessTimeOut);
                    if (nCount * THREAD_SLEEP_INTERVAL > WATCHDOG_SEND_INTERVAL)
                    {
                        processTimeOut++;
                       
                        nCount = 0;
                    }

                    nCount++;
                    Thread.Sleep(THREAD_SLEEP_INTERVAL);

                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                    WriteLog(string.Format("错误:{0}", ex.Message));

                }

            }
        }

        private void MoveFiles(String srcDir)
        {
            String[] files = Directory.GetFiles(srcDir);
            for (int i = 0; i < files.Length; i++)
            {
                String srcFile = files[i];
                String dstFile = srcFile.Replace(updateDir, runDir);

                if (File.Exists(dstFile))
                {
                    try
                    {
                        File.Delete(dstFile);
                    }
                    catch
                    {
                        WriteLog(String.Format("文件[{0}]删除失败,可能导致站机无法运行", dstFile));
                    }
                }
                try
                {
                    String dstDir = Path.GetDirectoryName(dstFile);
                    if (Directory.Exists(dstDir))
                    {
                        Directory.CreateDirectory(dstDir);
                    }
                    File.Move(srcFile, dstFile);
                }
                catch
                { 
                }

            }
           String[] dirs= Directory.GetDirectories(srcDir);
           for (int i = 0; i < dirs.Length; i++)
           {
               MoveFiles(dirs[i]);
           }
           
            
        }

        public void ResetWatch()
        {
            //收到看门狗消息，重置超时计数器
            processTimeOut = 0;

        }


        private bool ProcessRunning()
        {
            //进程是否正在运行
            bool boResult = false;
            Process[] processOnComputer = Process.GetProcesses();
            foreach (System.Diagnostics.Process p in processOnComputer)
            {
                //p.MainModule.FileName
                if (!p.ProcessName.Equals(processName)) continue;
                boResult = true;
                break;
            }

            return boResult;
        }

        private bool KillProcess(bool force)
        {
            //终止进程
            bool boResult = false;
            Process[] processOnComputer = Process.GetProcesses();
            foreach (System.Diagnostics.Process p in processOnComputer)
            {
                //p.MainModule.FileName
                if (p.ProcessName.Equals(processName))
                {
                    if (force)
                    {
                        p.Kill();
                        boResult = true;
                        WriteLog("强制杀死进程！");

                    }
                    else
                    {
                        boResult = p.CloseMainWindow();
                        WriteLog("关闭进程.");

                    }

                    break;
                }
            }

            return boResult;
        }

        private void StartProcess()
        {
            //启动进程
            Process.Start(processPath);
            WriteLog("重启进程.");
        }

        string logFile = "CSMDeamon.log";
        private void WriteLog(string text)
        {
            //写入日志
            string textLine = string.Format("[ {0} ]  {1}\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), text);
            File.AppendAllText(logFile, textLine, Encoding.Default);
        }
    }
}
